package com.chukun.gateway.core;

import com.alibaba.fastjson2.JSON;
import com.chukun.gateway.common.definition.ServiceDefinition;
import com.chukun.gateway.common.instance.ServiceInstance;
import com.chukun.gateway.common.manager.DynamicConfigManager;
import com.chukun.gateway.common.utils.NetUtils;
import com.chukun.gateway.common.utils.TimeUtils;
import com.chukun.gateway.config.api.ConfigCenter;
import com.chukun.gateway.core.config.GatewayConfig;
import com.chukun.gateway.core.config.GatewayConfigLoader;
import com.chukun.gateway.core.container.Container;
import com.chukun.gateway.registry.api.RegisterCenter;
import com.chukun.gateway.registry.api.RegisterCenterListener;
import lombok.extern.slf4j.Slf4j;

import java.util.Map;
import java.util.ServiceLoader;
import java.util.Set;

import static com.chukun.gateway.common.constants.GatewayCommonConst.COLON_SEPARATOR;

/**
 * @author chukun
 * @version 1.0.0
 * @description api网关启动类
 * @createTime 2023/11/19 20:53
 */
@Slf4j
public class ApiGatewayBootstrap {

    public static void main( String[] args ) {
        //加载网关核心静态配置
        GatewayConfig config = GatewayConfigLoader.getInstance().load(args);
        System.out.println(config.getPort());

        //插件初始化
        //配置中心管理器初始化，连接配置中心，监听配置的新增、修改、删除
        ConfigCenter configCenter = configAndSubscribe(config);

        //启动容器
        Container container = new Container(config);
        container.start();

        //连接注册中心，将注册中心的实例加载到本地

        //连接注册中心，将注册中心的实例加载到本地
        final RegisterCenter registerCenter = registerAndSubscribe(config);

        //服务优雅关机
        //收到kill信号时调用
        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                registerCenter.deregister(buildGatewayServiceDefinition(config),
                        buildGatewayServiceInstance(config));
            }
        });
        //服务优雅关机

    }

    /**
     * 构建配置中心
     * @param config
     * @return
     */
    private static ConfigCenter configAndSubscribe(GatewayConfig config) {
        ServiceLoader<ConfigCenter> serviceLoader = ServiceLoader.load(ConfigCenter.class);
        final ConfigCenter configCenter = serviceLoader.findFirst().orElseThrow(() -> {
            log.error("not found ConfigCenter impl");
            return new RuntimeException("not found ConfigCenter impl");
        });
        configCenter.init(config.getRegistryAddress(), config.getEnv());
        configCenter.subscribeRulesChange(rules -> DynamicConfigManager.getInstance().putAllRule(rules));

        return configCenter;
    }

    /**
     * 构建注册中心
     * @param config
     * @return
     */
    private static RegisterCenter registerAndSubscribe(GatewayConfig config) {
        ServiceLoader<RegisterCenter> serviceLoader = ServiceLoader.load(RegisterCenter.class);
        final RegisterCenter registerCenter = serviceLoader.findFirst().orElseThrow(() -> {
            log.error("not found RegisterCenter impl");
            return new RuntimeException("not found RegisterCenter impl");
        });
        registerCenter.init(config.getRegistryAddress(), config.getEnv());

        //构造网关服务定义和服务实例
        ServiceDefinition serviceDefinition = buildGatewayServiceDefinition(config);
        ServiceInstance serviceInstance = buildGatewayServiceInstance(config);

        //注册
        registerCenter.register(serviceDefinition, serviceInstance);

        //订阅
        registerCenter.subscribeAllServices(new RegisterCenterListener() {
            @Override
            public void onChange(ServiceDefinition serviceDefinition, Set<ServiceInstance> serviceInstanceSet) {
                log.info("refresh service and instance: {} {}", serviceDefinition.getUniqueId(),
                        JSON.toJSON(serviceInstanceSet));
                DynamicConfigManager manager = DynamicConfigManager.getInstance();
                manager.addServiceInstance(serviceDefinition.getUniqueId(), serviceInstanceSet);
            }
        });
        return registerCenter;
    }

    /**
     * 构建服务的实例信息
     * @param config
     * @return
     */
    private static ServiceInstance buildGatewayServiceInstance(GatewayConfig config) {
        String localIp = NetUtils.getLocalIp();
        int port = config.getPort();
        ServiceInstance serviceInstance = new ServiceInstance();
        serviceInstance.setServiceInstanceId(localIp + COLON_SEPARATOR + port);
        serviceInstance.setIp(localIp);
        serviceInstance.setPort(port);
        serviceInstance.setRegisterTime(TimeUtils.currentTimeMillis());
        return serviceInstance;
    }

    /**
     * 构建服务的定义信息
     * @param config
     * @return
     */
    private static ServiceDefinition buildGatewayServiceDefinition(GatewayConfig config) {
        ServiceDefinition serviceDefinition = new ServiceDefinition();
        serviceDefinition.setInvokerMap(Map.of());
        serviceDefinition.setUniqueId(config.getApplicationName());
        serviceDefinition.setServiceId(config.getApplicationName());
        serviceDefinition.setEnvType(config.getEnv());
        return serviceDefinition;
    }
}
